#ifndef JSTRING_H
#define JSTRING_H

#include <JXQCore/JXQGlobal>
#include <JXQCore/JList>
#include <JXQCore/JDebug>
#include <string>
#include <memory>
#include <cstring>

#ifdef _MSC_VER
# pragma warning(disable:4146)
#endif

namespace JXQ
{

template <bool...B> class BoolList {};

template <typename T> struct __is_char { enum { value = false }; };
template <> struct __is_char<char>     { enum { value = true  }; };

template <typename T> struct __is_wchar { enum { value = false }; };
template <> struct __is_wchar<wchar_t>  { enum { value = true  }; };

template <typename T> struct __is_bool { enum { value = false }; };
template <> struct __is_bool<bool>     { enum { value = true  }; };

template <typename TChar>
class JBasicString : public std::basic_string<TChar>
{
	static_assert(__is_char<TChar>::value or __is_wchar<TChar>::value,
				  "Character type error: the type must be char/wchar_t");

public:
	typedef std::basic_string<TChar>  Base;
	typedef typename Base::size_type  size_type;
	using std::basic_string<TChar>::basic_string;

	JBasicString();
	JBasicString(const std::basic_string<TChar> &other);
	JBasicString(std::basic_string<TChar> &&other) noexcept;
	JBasicString(const JBasicString &other);
	JBasicString(JBasicString &&other) noexcept;

public:
	const JBasicString &operator=(const JBasicString &other);
	const JBasicString &operator=(JBasicString &&other) noexcept;
	const TChar &operator[](size_type index) const;
	TChar &operator[](size_type index);

public:
	const JBasicString &replace(const JBasicString &find, const JBasicString &target,
						   size_t index = 0, bool all = true);

public: // 查找
	bool contains(const TChar *str) const;
	bool contains(const Base &str) const;
	int indexof(const TChar *str, int index = 0) const;
	int indexof(const Base &str, int index = 0) const;
	int lastIndexof(const TChar *str, int index = -1) const;
	int lastIndexof(const Base &str, int index = -1) const;

public:
	template <typename ...Args> // 格式化输出
	static JBasicString sprintf(const Base &format, Args&&...args);

public:
	template <typename T> inline
	typename std::enable_if<
		not __is_float<T>::value and
		__is_primitive<T>::value,
	JBasicString>::type
	arg(T i, int radix = 10) const; //匹配整形

	template <typename T> inline
	typename std::enable_if<
		__is_float<T>::value,
	JBasicString>::type
	arg(T i, int decimals = 1) const; //匹配浮点型

	JBasicString arg(TChar c, bool isNum = false, int radix = 10) const; //一个字符
	JBasicString arg(const void *p) const; //未知指针

	// 字符串相关
	JBasicString arg(const TChar *str) const;
	JBasicString arg(const Base &str) const;

	template <typename T>
	typename std::enable_if<
		__is_bool<T>::value,
	JBasicString>::type
	arg(bool value, const JBasicString &trueStr = "true",
		const JBasicString &falseStr = "false") const;

private:
	template <typename T>
	struct is_convertible_to_string_helper :
			std::integral_constant<bool,
			std::is_convertible<T, TChar*>::value or
			std::is_convertible<T, JBasicString<TChar>>::value or
			std::is_convertible<T, std::string>::value> {};

	template <typename T>
	struct is_convertible_to_string :
			is_convertible_to_string_helper<typename std::decay<T>::type> {};

public: // 字符串连续替换(递归)
	template <typename...Args> // 算法需要调整优化，采用单次循环
	typename std::enable_if<
		std::is_same<
			BoolList<is_convertible_to_string<Args>::value..., true>,
			BoolList<true, is_convertible_to_string<Args>::value...>
		>::value,
	JBasicString>::type arg(const TChar *str, Args&&...args) const
	{
		auto tmp = arg(str);
		return tmp.arg(std::forward<Args>(args)...);
	}

	template <typename...Args>
	typename std::enable_if<
		std::is_same<
			BoolList<is_convertible_to_string<Args>::value..., true>,
			BoolList<true, is_convertible_to_string<Args>::value...>
		>::value,
	JBasicString>::type arg(const Base &str, Args&&...args) const
	{
		auto tmp = arg(str.c_str());
		return tmp.arg(std::forward<Args>(args)...);
	}

	template <typename...Args>
	typename std::enable_if<
		std::is_same<
			BoolList<is_convertible_to_string<Args>::value..., true>,
			BoolList<true, is_convertible_to_string<Args>::value...>
		>::value,
	JBasicString>::type arg(const JBasicString &str, Args&&...args) const
	{
		auto tmp = arg(str.c_str());
		return tmp.arg(std::forward<Args>(args)...);
	}

public:
	JBasicStringList<TChar>
	split(const JBasicString &separator = JBasicString(1,J_SCT(TChar,0x20))) const;

public: // 数字转字符串
	template <typename T>
	static typename std::enable_if<
		not __is_float<T>::value and std::is_signed<T>::value,
	JBasicString>::type number(T num, int radix = 10);

	template <typename T>
	static typename std::enable_if<
		not __is_float<T>::value and not std::is_signed<T>::value,
	JBasicString>::type number(T num, int radix = 10);

	static JBasicString<TChar> number(float num, int decimals = 1);
	static JBasicString<TChar> number(double num, int decimals = 1);
	static JBasicString<TChar> number(long double num, int decimals = 1);

public: // 字符串转数字
	inline char toInt8(int radix = 10) const;
	inline uint8_t toUInt8(int radix = 10) const;
	inline short toShort(int radix = 10) const;
	inline uint16_t toUShort(int radix = 10) const;
	inline int toInt(int radix = 10) const;
	inline unsigned int toUInt(int radix = 10) const;
	inline long toLong(int radix = 10) const;
	inline unsigned long toULong(int radix = 10) const;
	inline int64_t toLLong(int radix = 10) const;
	inline uint64_t toULLong(int radix = 10) const;
	inline float toFloat(int decimals = 2) const;
	inline double toDouble(int decimals = 2) const;
	inline long double toLDouble(int decimals = 2) const;

public:
	inline operator const TChar*() const;
	inline std::basic_string<TChar> toStdString() const;

private:
	static uint32_t argFindIndex(const TChar *str, int size, int *arr, int &formatLenght);

	template <typename T>
	static uint32_t getBitNums(T num, int decimals = -1);

	template <typename T>
	static typename std::enable_if< not __is_float<T>::value,
	void>::type numToStr(T num, TChar *str, int radix);

	template <typename T>
	JBasicString argNumber(T i, int parameter) const;
};

/*----------------------------------------------------------------------------------------------------*/

#ifdef UNICODE //user custom macro
typedef JBasicString<wchar_t>  JString;
#else
typedef JBasicString<char>  JString;
#endif //UNICODE

/*----------------------------------------------------------------------------------------------------*/

typedef JBasicString<wchar_t>  JStringW;

template <typename TChar>
inline JBasicString<TChar>::JBasicString() :
	Base() {}

template <typename TChar>
inline JBasicString<TChar>::JBasicString(const std::basic_string<TChar> &other) :
	Base(other) {}

template <typename TChar>
inline JBasicString<TChar>::JBasicString(std::basic_string<TChar> &&other) noexcept :
	Base(std::forward<JBasicString>(other)) {}

template <typename TChar>
inline JBasicString<TChar>::JBasicString(const JBasicString &other) :
	Base(other) {}

template <typename TChar>
inline JBasicString<TChar>::JBasicString(JBasicString &&other) noexcept :
	Base(std::forward<JBasicString<TChar>>(other)) {}

template <typename TChar>
inline const JBasicString<TChar> &JBasicString<TChar>::operator=(const JBasicString &other)
{ Base::operator=(other); return *this; }

template <typename TChar>
inline const JBasicString<TChar> &JBasicString<TChar>::operator=(JBasicString &&other) noexcept
{ Base::operator=(std::forward<JBasicString<TChar>>(other)); return *this; }

template <typename TChar>
inline const TChar &JBasicString<TChar>::operator[](size_type index) const
{ return Base::operator[](index); }

template <typename TChar>
inline TChar &JBasicString<TChar>::operator[](size_type index)
{ return Base::operator[](index); }

template <typename TChar>
const JBasicString<TChar> &JBasicString<TChar>::replace
(const JBasicString<TChar> &find, const JBasicString &target, size_t index, bool all)
{
	do {
		index = this->find(find.c_str(), index);
		Base::replace(index, find.size(), target.c_str());
		index += find.size();
	}
	while( all and index <= this->size() - find.size() );
	return *this;
}

template <typename TChar>
inline bool JBasicString<TChar>::contains(const TChar *str) const
{ return find(str) != this->npos; }

template <typename TChar>
inline bool JBasicString<TChar>::contains(const Base &str) const
{ return find(str) != this->npos; }

template <typename TChar>
inline int JBasicString<TChar>::indexof(const TChar *str, int index) const
{
	auto res = find(str, index);
	return res==this->npos? -1 : J_SCT(int,res);
}

template <typename TChar>
inline int JBasicString<TChar>::indexof(const Base &str, int index) const
{
	return indexof(str.c_str(), index);
}

template <typename TChar>
inline int JBasicString<TChar>::lastIndexof(const TChar *str, int index) const
{
	if( index < 0 )
		index = this->size();
	auto res = rfind(str, index);
	return res==this->npos? -1 : J_SCT(int,res);
}

template <typename TChar>
int JBasicString<TChar>::lastIndexof(const Base &str, int index) const
{
	return lastIndexof(str.c_str(), index);
}

template <typename ...Args>
inline int snprintf (char *__restrict __s, size_t __maxlen, const char *__restrict __format, Args&&...args) noexcept
{ return ::snprintf(__s, __maxlen, __format, std::forward<Args>(args)...); }

template <typename ...Args>
inline int snprintf (wchar_t *__restrict __s, size_t __maxlen, const wchar_t *__restrict __format, Args&&...args) noexcept
{ return ::swprintf(__s, __maxlen, __format, std::forward<Args>(args)...); }

template <typename TChar>
template <typename ...Args>
JBasicString<TChar> JBasicString<TChar>::sprintf(const Base &format, Args&&...args)
{
	auto size = JXQ::snprintf(nullptr, 0, format.c_str(), args...) + 1;
	auto buf = std::unique_ptr<TChar>(new TChar[size+1]);

	JXQ::snprintf(buf.get(), size, format.c_str(), args...);
	return JBasicString(buf.get());
}

template <typename TChar>
template <typename T> inline
typename std::enable_if<
	not __is_float<T>::value and
	__is_primitive<T>::value,
JBasicString<TChar>>::type
JBasicString<TChar>::arg(T i, int radix) const //匹配整形
{
	return argNumber(i, radix);
}

template <typename TChar>
template <typename T> inline
typename std::enable_if<
	__is_float<T>::value,
JBasicString<TChar>>::type
JBasicString<TChar>::arg(T i, int decimals) const //匹配浮点型
{
	return argNumber(i, decimals);
}

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::arg(TChar c, bool isNum, int radix) const
{
	int format_len = 0;
	int arr[100] = {0};
	auto tmp = *this;
	int num = argFindIndex(tmp.c_str(), this->size(), arr, format_len);
	if( num == 0 )
		return *this;

	if( isNum )
	{
		for(int index=num-1; index>=0; index--)
		{
			tmp.erase(arr[index], format_len);
			tmp.insert(arr[index], number(c,radix));
		}
	}
	else
	{
		for(int index=num-1; index>=0; index--)
		{
			tmp.erase(arr[index], format_len);
			tmp.insert(arr[index], Base(c,1));
		}
	}
	return tmp;
}

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::arg(const void *p) const
{
	int format_len = 0;
	int arr[100] = {0};
	auto tmp = *this;
	int num = argFindIndex(tmp.c_str(), this->size(), arr, format_len);
	if( num == 0 )
		return *this;

	static constexpr TChar format[] =
#ifdef J_OS_64BIT
	{'0', 'x', '%', 'L', 'X'};
#else
	{'0', 'x', '%', 'l', 'X'};
#endif

	TChar str_p[32] = {};
	sprintf(str_p, format, J_RCT(AddressBitsWide, p));

	for(int index=num-1; index>=0; index--)
	{
		tmp.erase(arr[index], format_len);
		tmp.insert(arr[index], str_p);
	}
	return tmp;
}

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::arg(const TChar *str) const
{
	int format_len = 0;
	int arr[100] = {0};
	auto tmp = *this;
	int num = argFindIndex(tmp.c_str(), this->size(), arr, format_len);
	if( num == 0 )
		return *this;

	for(int index=num-1; index>=0; index--)
	{
		tmp.erase(arr[index], format_len);
		tmp.insert(arr[index], str);
	}
	return tmp;
}

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::arg(const Base &str) const
{
	return arg(str.c_str());
}

template <typename TChar>
template <typename T> inline
typename std::enable_if<
	__is_bool<T>::value,
JBasicString<TChar>>::type
JBasicString<TChar>::arg(bool value, const JBasicString &trueStr, const JBasicString &falseStr) const
{
	return arg(value? trueStr.c_str() : falseStr.c_str());
}

template <typename TChar>
JBasicStringList<TChar> JBasicString<TChar>::split(const JBasicString<TChar> &separator) const
{
	JBasicStringList<TChar> list;
	size_t index = 0;
	size_t length = 0;

	while( index < this->size() )
	{
		size_t pos = this->find(separator.c_str(), index);
		if( pos == JBasicString::npos )
		{
			list.append(this->substr(index, this->size()-index));
			break;
		}

		length = pos - index;
		list.append(this->substr(index, length));
		index += length + separator.size();
	}
	return list;
}

template <typename TChar>
template <typename T>
typename std::enable_if<
	not __is_float<T>::value and std::is_signed<T>::value,
JBasicString<TChar>>::type JBasicString<TChar>::number(T num, int radix)
{
	if( radix < 2 or radix > 16 ) //2到16进制足够用了
		return JBasicString<TChar>();

	int size = getBitNums(num) + 2;
	TChar *str = nullptr;

	if( num < 0 )
	{
		str = new TChar[++size];
		str[0] = '-';
		numToStr(-num, str+1, radix);
	}
	else
	{
		str = new TChar[size];
		numToStr(num, str, radix);
	}

	std::shared_ptr<TChar> tmp(str);
	return JBasicString<TChar>(str);
}

template <typename TChar>
template <typename T>
typename std::enable_if<
	not __is_float<T>::value and not std::is_signed<T>::value,
JBasicString<TChar>>::type JBasicString<TChar>::number(T num, int radix)
{
	if( radix < 2 or radix > 16 ) //2到16进制足够用了
		return JBasicString<TChar>();

	int size = getBitNums(num) + 2;
	TChar *str = new TChar[size];
	numToStr(num, str, radix);

	std::shared_ptr<TChar> tmp(str);
	return JBasicString<TChar>(str);
}

JXQLIB_EXPORT JBasicString<char> __floatToString(float num, int decimals, const char*);
JXQLIB_EXPORT JBasicString<char> __doubleToString(double num, int decimals, const char*);
JXQLIB_EXPORT JBasicString<char> __LDoubleToString(long double num, int decimals, const char*);
JXQLIB_EXPORT JBasicString<wchar_t> __floatToString(float num, int decimals, const wchar_t*);
JXQLIB_EXPORT JBasicString<wchar_t> __doubleToString(double num, int decimals, const wchar_t*);
JXQLIB_EXPORT JBasicString<wchar_t> __LDoubleToString(long double num, int decimals, const wchar_t*);

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::number(float num, int decimals)
{
	return __floatToString(num, decimals, (TChar*)(0));
}

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::number(double num, int decimals)
{
	return __doubleToString(num, decimals, (TChar*)(0));
}

template <typename TChar>
JBasicString<TChar> JBasicString<TChar>::number(long double num, int decimals)
{
	return __LDoubleToString(num, decimals, (TChar*)(0));
}

// math库中的pow是浮点数计算，影响效率，这里的字符串相关算法不需要浮点计算
template <typename T>
T pow(int base, uint32_t exponent)
{
	if( exponent == 0 )
		return 1;

	T tmp = J_SCT(T, base);
	while( --exponent )
		tmp *= base;

	return tmp;
}

template <typename TChar, typename T>
T toNumber(const TChar *str, size_t size, int radix)
{
	if( radix < 2 or radix > 16 )
		return 0;

	size_t i = 0;
	uint32_t exponent = 0;

	if( str[0] == '-' )
		++i;

	if( str[i] == '0' )
	{
		if( radix == 8 )
			++i;
		else if( radix == 16 and ( str[1] == 'x' or str[1] == 'X' ) )
			i += 2;
	}
	else if( radix == 2 )
	{
		if( str[size-1] == 'b' or str[size-1] == 'B' )
			--size;
	}

	exponent = J_SCT(uint32_t, size - 1 - i);
	T num = 0;

	for(; i<size; i++)
	{
		if( str[i] >= '0' and str[i] <= '9' )
			num += (str[i] - '0') * pow<T>(radix, exponent--);
		else if( str[i] >= 'A' and str[i] <= 'F' )
			num += (str[i] - 55) * pow<T>(radix, exponent--);
		else if( str[i] >= 'a' and str[i] <= 'f' )
			num += (str[i] - 87) * pow<T>(radix, exponent--);
	}
	return str[0] == '-'? -num : num;
}

template <typename TChar>
inline char JBasicString<TChar>::toInt8(int radix) const
{
	return toNumber<TChar, int8_t>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline uint8_t JBasicString<TChar>::toUInt8(int radix) const
{
	return toNumber<TChar, uint8_t>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline short JBasicString<TChar>::toShort(int radix) const
{
	return toNumber<TChar, int16_t>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline uint16_t JBasicString<TChar>::toUShort(int radix) const
{
	return toNumber<TChar, uint16_t>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline int JBasicString<TChar>::toInt(int radix) const
{
	return toNumber<TChar, int>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline unsigned int JBasicString<TChar>::toUInt(int radix) const
{
	return toNumber<TChar, unsigned int>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline long JBasicString<TChar>::toLong(int radix) const
{
	return toNumber<TChar, long>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline unsigned long JBasicString<TChar>::toULong(int radix) const
{
	return toNumber<TChar, unsigned long>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline int64_t JBasicString<TChar>::toLLong(int radix) const
{
	return toNumber<TChar, int64_t>(this->c_str(), this->size(), radix);
}

template <typename TChar>
inline uint64_t JBasicString<TChar>::toULLong(int radix) const
{
	return toNumber<TChar, uint64_t>(this->c_str(), this->size(), radix);
}

JXQLIB_EXPORT float __stringToFloat(const JBasicString<char> &str, int decimals);
JXQLIB_EXPORT double __stringToDouble(const JBasicString<char> &str, int decimals);
JXQLIB_EXPORT long double __stringToLDouble(const JBasicString<char> &str, int decimals);
JXQLIB_EXPORT float __stringToFloat(const JBasicString<wchar_t> &str, int decimals);
JXQLIB_EXPORT double __stringToDouble(const JBasicString<wchar_t> &str, int decimals);
JXQLIB_EXPORT long double __stringToLDouble(const JBasicString<wchar_t> &str, int decimals);

template <typename TChar>
inline float JBasicString<TChar>::toFloat(int decimals) const
{
	return __stringToFloat(this->c_str(), decimals);
}

template <typename TChar>
inline double JBasicString<TChar>::toDouble(int decimals) const
{
	return __stringToDouble(this->c_str(), decimals);
}

template <typename TChar>
inline long double JBasicString<TChar>::toLDouble(int decimals) const
{
	return __stringToLDouble(this->c_str(), decimals);
}

template <typename TChar>
inline JBasicString<TChar>::operator const TChar*() const
{
	return this->c_str();
}

template <typename TChar>
inline std::basic_string<TChar> JBasicString<TChar>::toStdString() const
{
	return this->c_str();
}

template <typename TChar>
uint32_t JBasicString<TChar>::argFindIndex(const TChar *str, int size, int *arr, int &formatLenght)
{
	int min = 100; //格式的数字范围 0-99，所以最小号的初始值是100
	int num = 0;
	formatLenght = 3;

	for(int i=0; i<size; i++) //遍历自己
	{
		// 找到 %[0-9] 的格式
		if( str[i] == '%' and str[i+1] >= '0' and str[i+1] <= '9' )
		{
			if( str[i+2] < '0' or str[i+2] > '9' ) //最小的格式的数字是各位数
			{
				formatLenght = 2; //最小的已经是个位数，不需要再判断十位数
				int tmp = str[i+1] - '0';

				if( tmp < min ) //寻找最小的格式数字
				{
					num = 1;
					min = tmp;
					arr[num-1] = i; //记录对应的索引位置
				}
				else if( tmp == min )
					arr[num++] = i;
			}
			else if( formatLenght == 3 ) //同上
			{
				int tmp = (str[i+1] - '0') * 10 + (str[i+2] - '0');

				if( tmp < min )
				{
					num = 1;
					min = tmp;
					arr[num-1] = i;
				}
				else if( tmp == min )
					arr[num++] = i;
			}
			i += 2;
		}
	}
	return num;
}

template <typename TChar>
template <typename T> // decimals不大于0, 则num当成整形处理
uint32_t JBasicString<TChar>::getBitNums(T num, int decimals)
{
	int ret = 1;
	if( decimals <= 0 )
	{
		while( num /= 10 )
			ret++;
		return ret;
	}
	ret += 1 + decimals;
	while( num /= 10 )
		ret++;
	return ret;
}

template <typename TChar>
template <typename T>
typename std::enable_if<not __is_float<T>::value,
void>::type JBasicString<TChar>::numToStr(T num, TChar *str, int radix)
{
	static constexpr char index[] = "0123456789ABCDEF";

	int i = 0;
	do //转换
	{
		str[i++] = J_SCT(TChar, index[num%radix]);
		num /= J_SCT(T, radix);
	}
	while(num);
	str[i] = '\0';

	// 逆序
	int k = str[0] == '-'? 1:0; //1:十进制负数
	int m = (i-1) >> 1;

	for(int j=k; j<=m; j++)
	{
		TChar temp;
		temp = str[j];
		str[j] = str[i-1+k-j];
		str[i-1+k-j] = temp;
	}
}

template <typename TChar>
template <typename T>
JBasicString<TChar> JBasicString<TChar>::argNumber(T i, int parameter) const
{
	int format_len = 0;
	int arr[100] = {0};
	auto tmp = *this;
	int num = argFindIndex(tmp.c_str(), this->size(), arr, format_len);
	if( num == 0 )
		return *this;

	for(int index=num-1; index>=0; index--)
	{
		tmp.erase(arr[index], format_len);
		tmp.insert(arr[index], number(i, parameter));
	}
	return tmp;
}

template <typename T> struct __is_CppStringC                { enum { value = false }; };
template <> struct __is_CppStringC<std::basic_string<char>> { enum { value = true  }; };
template <> struct __is_CppStringC<JBasicString<char>>      { enum { value = true  }; };

template <typename T> struct __is_CppStringW                   { enum { value = false }; };
template <> struct __is_CppStringW<std::basic_string<wchar_t>> { enum { value = true  }; };
template <> struct __is_CppStringW<JBasicString<wchar_t>>      { enum { value = true  }; };

template <typename T> struct __is_CppString                    { enum { value = false }; };
template <> struct __is_CppString<std::basic_string<char>>    { enum { value = true  }; };
template <> struct __is_CppString<std::basic_string<wchar_t>> { enum { value = true  }; };
template <> struct __is_CppString<JBasicString<char>>          { enum { value = true  }; };
template <> struct __is_CppString<JBasicString<wchar_t>>       { enum { value = true  }; };

template <typename TChar>
inline JDebug &operator<<(JDebug &d, const JBasicString<TChar> *str)
{
	return d << J_SCT(const std::basic_string<TChar>*, str);
}

template <typename TChar>
inline JDebug &operator<<(JDebug &&d, const JBasicString<TChar> *str)
{
	return d << J_SCT(const std::basic_string<TChar>*, str);
}

template <typename TChar>
inline JDebug &operator<<(JDebug &d, const JBasicString<TChar> &str)
{
	return d << &str;
}

template <typename TChar>
inline JDebug &operator<<(JDebug &&d, const JBasicString<TChar> &str)
{
	return d << &str;
}

// MSVC is annoying

} //namespace JXQ


#endif //JSTRING_H
